#pragma once 
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

const int gcap = 5;

template <class T>
class BlockQueue{
public:

    BlockQueue(const int capacity = gcap):_capacity(capacity) {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_consumerCond, nullptr);
        pthread_cond_init(&_productorCond, nullptr);

    }

    bool isFull(){
        return _q.size() == _capacity;
    }

    void push(const T &in){
        pthread_mutex_lock(&_mutex);

        //注意：1、当有多个生产者的时候，若消费者对生产者进行误唤醒，会导致超容，所以需要while判断isFull()，消费者同理

        //当队列已满，生产者休眠
        while(isFull()){
            //休眠的同时释放锁
            pthread_cond_wait(&_productorCond, &_mutex);
            //被唤醒后重新持有锁
        }
        _q.push(in);
        //push后队列一定不为空，此时唤醒消费者
        if(_q.size()>=3){
            pthread_cond_signal(&_consumerCond);
        }
        

        pthread_mutex_unlock(&_mutex);
    }

    bool isEmpty(){
        return _q.empty();
    }

    void pop(T *out){
        pthread_mutex_lock(&_mutex);

        //当队列为空，消费者休眠
        while(isEmpty()){
            pthread_cond_wait(&_consumerCond, &_mutex);
        }
        *out = _q.front();
        _q.pop();
        //pop后队列一定不满，此时唤醒消费者
        if(_q.size()<3){
            pthread_cond_signal(&_productorCond);
        }
        

        pthread_mutex_unlock(&_mutex);

    }

    ~BlockQueue(){
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumerCond);
        pthread_cond_destroy(&_productorCond);
    }

private:
    queue<T> _q;
    int _capacity;
    //只有一把锁的原因：生产和消费用的是同一个队列，存在访问互斥
    pthread_mutex_t _mutex;
    //消费者的条件变量，empty - wait
    pthread_cond_t _consumerCond;
    //生产者的条件变量，full - wait
    pthread_cond_t _productorCond;
};